package com.cmeduSystem.webadmin.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 从钉钉同步手机号到本地数据库
 * 根据本地数据库中的用户姓名与钉钉用户信息比对，更新手机号
 */
public class DingTalkToDbSync {
    // 钉钉配置
    private static final String APP_KEY = "dingpnqim4zo2sn603nz";
    private static final String APP_SECRET = "-QB4AHw_-6lQadpaFwAUPrZn3sijkPcru5G5L-Z13vP7C38R2ogN1bF22BETokMm";
    private static final String DINGTALK_API_BASE = "https://oapi.dingtalk.com";

    // 数据库配置
    private static final String DB_URL = "jdbc:postgresql://127.0.0.1:5432/postgres?currentSchema=public";
    private static final String DB_USER = "postgres";
    private static final String DB_PASSWORD = "123456";

    /**
     * 获取钉钉访问令牌
     */
    public String getAccessToken() throws IOException {
        String url = DINGTALK_API_BASE + "/gettoken?appkey=" + APP_KEY + "&appsecret=" + APP_SECRET;

        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpGet httpGet = new HttpGet(url);
            try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    String result = EntityUtils.toString(entity, StandardCharsets.UTF_8);
                    JSONObject jsonObject = JSON.parseObject(result);

                    if (jsonObject.getInteger("errcode") == 0) {
                        return jsonObject.getString("access_token");
                    } else {
                        throw new RuntimeException("获取access_token失败: " + jsonObject.getString("errmsg"));
                    }
                }
            }
        }
        throw new RuntimeException("获取access_token失败");
    }

    /**
     * 获取部门列表
     */
    public List<Department> getDepartments(String accessToken) throws IOException {
        String url = DINGTALK_API_BASE + "/department/list?access_token=" + accessToken;

        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpGet httpGet = new HttpGet(url);
            try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    String result = EntityUtils.toString(entity, StandardCharsets.UTF_8);
                    JSONObject jsonObject = JSON.parseObject(result);

                    if (jsonObject.getInteger("errcode") == 0) {
                        JSONArray deptArray = jsonObject.getJSONArray("department");
                        return deptArray.toJavaList(Department.class);
                    } else {
                        throw new RuntimeException("获取部门列表失败: " + jsonObject.getString("errmsg"));
                    }
                }
            }
        }
        throw new RuntimeException("获取部门列表失败");
    }

    /**
     * 获取部门用户列表
     */
    public List<DingTalkUser> getDepartmentUsers(String accessToken, String deptId) throws IOException {
        String url = DINGTALK_API_BASE + "/user/list?access_token=" + accessToken + "&department_id=" + deptId + "&offset=0&size=100";

        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpGet httpGet = new HttpGet(url);
            try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    String result = EntityUtils.toString(entity, StandardCharsets.UTF_8);
                    JSONObject jsonObject = JSON.parseObject(result);

                    if (jsonObject.getInteger("errcode") == 0) {
                        JSONArray userArray = jsonObject.getJSONArray("userlist");
                        return userArray.toJavaList(DingTalkUser.class);
                    } else {
                        throw new RuntimeException("获取部门用户失败: " + jsonObject.getString("errmsg"));
                    }
                }
            }
        }
        throw new RuntimeException("获取部门用户失败");
    }

    /**
     * 获取所有钉钉用户，按姓名建立映射
     */
    public Map<String, DingTalkUser> getAllDingTalkUsers() throws IOException {
        Map<String, DingTalkUser> userMap = new HashMap<>();
        String accessToken = getAccessToken();

        // 获取所有部门
        List<Department> departments = getDepartments(accessToken);

        // 遍历部门获取所有用户
        for (Department dept : departments) {
            List<DingTalkUser> users = getDepartmentUsers(accessToken, dept.getId());
            for (DingTalkUser user : users) {
                // 按姓名建立映射，处理可能的重名情况
                String key = user.getName().trim();
                if (!userMap.containsKey(key)) {
                    userMap.put(key, user);
                } else {
                    System.out.println("警告：发现重名用户 " + key + "，仅保留第一个");
                }
            }
            // 避免API调用过于频繁
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }

        return userMap;
    }

    /**
     * 从数据库获取需要更新手机号的用户
     */
    public List<LocalUser> getLocalUsersNeedUpdate() throws SQLException {
        List<LocalUser> users = new ArrayList<>();
        String sql = "SELECT user_id, show_name, mobile FROM sys_user WHERE mobile IS NULL OR mobile = ''";

        try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
             PreparedStatement stmt = conn.prepareStatement(sql);
             ResultSet rs = stmt.executeQuery()) {

            while (rs.next()) {
                LocalUser user = new LocalUser();
                user.setId(rs.getLong("user_id"));
                user.setName(rs.getString("show_name").trim());
                user.setPhone(rs.getString("mobile"));
                users.add(user);
            }
        }
        return users;
    }

    /**
     * 更新本地数据库用户的手机号
     */
    public int updateLocalUserPhone(Long userId, String phone) throws SQLException {
        String sql = "UPDATE sys_user SET mobile = ?, update_time = NOW() WHERE user_id = ?";

        try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
             PreparedStatement stmt = conn.prepareStatement(sql)) {

            stmt.setString(1, phone);
            stmt.setLong(2, userId);
            return stmt.executeUpdate();
        }
    }

    /**
     * 执行同步操作
     */
    public SyncStats executeSync() {
        SyncStats stats = new SyncStats();

        try {
            // 获取所有钉钉用户，按姓名建立映射
            System.out.println("开始获取钉钉用户信息...");
            Map<String, DingTalkUser> dingTalkUsers = getAllDingTalkUsers();
            stats.setTotalDingTalkUsers(dingTalkUsers.size());
            System.out.println("获取到 " + dingTalkUsers.size() + " 个钉钉用户");

            // 获取本地需要更新手机号的用户
            System.out.println("开始获取本地需要更新的用户...");
            List<LocalUser> localUsers = getLocalUsersNeedUpdate();
            stats.setTotalLocalUsers(localUsers.size());
            System.out.println("获取到 " + localUsers.size() + " 个需要更新的本地用户");

            // 比对并更新
            for (LocalUser localUser : localUsers) {
                String userName = localUser.getName();

                if (dingTalkUsers.containsKey(userName)) {
                    DingTalkUser dingTalkUser = dingTalkUsers.get(userName);

                    // 检查手机号是否需要更新
                    if (dingTalkUser.getMobile() != null &&
                            (localUser.getPhone() == null || !localUser.getPhone().equals(dingTalkUser.getMobile()))) {

                        int rowsUpdated = updateLocalUserPhone(localUser.getId(), dingTalkUser.getMobile());
                        if (rowsUpdated > 0) {
                            stats.incrementSuccessCount();
                            System.out.println("更新用户 [" + userName + "] 的手机号为: " + dingTalkUser.getMobile());
                        } else {
                            stats.incrementFailCount();
                            System.out.println("更新用户 [" + userName + "] 失败");
                        }
                    } else {
                        stats.incrementNoChangeCount();
                        System.out.println("用户 [" + userName + "] 手机号无需更新");
                    }
                } else {
                    stats.incrementNoMatchCount();
                    System.out.println("未找到匹配的钉钉用户: " + userName);
                }
            }

        } catch (Exception e) {
            System.err.println("同步过程中发生错误: " + e.getMessage());
            e.printStackTrace();
            stats.setError(true);
            stats.setErrorMessage(e.getMessage());
        }

        return stats;
    }

    public static void main(String[] args) {
        DingTalkToDbSync syncTool = new DingTalkToDbSync();
        SyncStats stats = syncTool.executeSync();

        System.out.println("\n同步完成，统计信息:");
        System.out.println("钉钉用户总数: " + stats.getTotalDingTalkUsers());
        System.out.println("本地需要更新的用户总数: " + stats.getTotalLocalUsers());
        System.out.println("成功更新手机号: " + stats.getSuccessCount());
        System.out.println("无需更新的用户: " + stats.getNoChangeCount());
        System.out.println("未找到匹配的用户: " + stats.getNoMatchCount());
        System.out.println("更新失败的用户: " + stats.getFailCount());

        if (stats.isError()) {
            System.out.println("同步过程中发生错误: " + stats.getErrorMessage());
        }
    }

    // 部门实体类
    public static class Department {
        private String id;
        private String name;

        public String getId() { return id; }
        public void setId(String id) { this.id = id; }
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
    }

    // 钉钉用户实体类
    public static class DingTalkUser {
        private String userid;
        private String name;
        private String mobile;
        private String department;

        public String getUserid() { return userid; }
        public void setUserid(String userid) { this.userid = userid; }
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public String getMobile() { return mobile; }
        public void setMobile(String mobile) { this.mobile = mobile; }
        public String getDepartment() { return department; }
        public void setDepartment(String department) { this.department = department; }
    }

    // 本地用户实体类
    public static class LocalUser {
        private Long id;
        private String name;
        private String phone;

        public Long getId() { return id; }
        public void setId(Long id) { this.id = id; }
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public String getPhone() { return phone; }
        public void setPhone(String phone) { this.phone = phone; }
    }

    // 同步统计信息类
    public static class SyncStats {
        private int totalDingTalkUsers;
        private int totalLocalUsers;
        private int successCount;
        private int noChangeCount;
        private int noMatchCount;
        private int failCount;
        private boolean error;
        private String errorMessage;

        // getter和setter方法
        public int getTotalDingTalkUsers() { return totalDingTalkUsers; }
        public void setTotalDingTalkUsers(int totalDingTalkUsers) { this.totalDingTalkUsers = totalDingTalkUsers; }
        public int getTotalLocalUsers() { return totalLocalUsers; }
        public void setTotalLocalUsers(int totalLocalUsers) { this.totalLocalUsers = totalLocalUsers; }
        public int getSuccessCount() { return successCount; }
        public void incrementSuccessCount() { this.successCount++; }
        public int getNoChangeCount() { return noChangeCount; }
        public void incrementNoChangeCount() { this.noChangeCount++; }
        public int getNoMatchCount() { return noMatchCount; }
        public void incrementNoMatchCount() { this.noMatchCount++; }
        public int getFailCount() { return failCount; }
        public void incrementFailCount() { this.failCount++; }
        public boolean isError() { return error; }
        public void setError(boolean error) { this.error = error; }
        public String getErrorMessage() { return errorMessage; }
        public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }
    }
}

